/*
 函数：一组有名字的代码，用来完成某个特定的任务。
 */

import Cocoa

func printGreeting()
{
    print("Hello,playground.")
}

printGreeting()
/*
 func关键字后跟函数名来定义一个函数
 （）里放函数的参数，没有参数就是空的
 */


func printPersonalGreeting(name:String)
{
    print("Hello \(name),Welcome to your playground")
}
printPersonalGreeting(name: "Leo.Yang")


func divisionDescriptionFor(numerator:Double,denominator:Double)
{
    print("\(numerator) divided by \(denominator) equals \(numerator/denominator)")
}
divisionDescriptionFor(numerator: 9.0, denominator: 3.0)


//2.变长参数
/*
 接收零个或更多输入值作为实参。函数只能有一个变长参数，而且一般应该是参数列表中的最后一个
 要声明变长参数，用参数类型后面的三个点表示，如names:String...
 */

func printPersonalGreetings1(to names:String...)
{
    for name in names
    {
        print("Hello \(name),welcom to the playground.");
    }
}

printPersonalGreetings1(to: "Alex","Chris","Drew");

//3.默认参数值
func divisionDescriptionFor1(numerator:Double,denominator:Double,withPunctuation punctuation:String = "!")
{
    print("\(numerator)divided by \(denominator) eausls \(numerator/denominator)\(punctuation)")
}
divisionDescriptionFor1(numerator: 9.0, denominator: 3.0)


//in-out
/*
 处于某种原因，函数有时候需要修改实参的值，in-out参数能够让函数影响函数体以外的变量。有两个主意事项，首先，in-out参数不能有默认值，其次，变长参数不能标记为inout。
 
 */
var error = "The request failed:"
func appendErrorCode(_ code:Int,toErrorString errorString:inout String)//在参数名钱用_会使得函数并调用时省去外部名，由于这个参数名是跟在函数名后面，调用的时候没必要用到这个名字。
{
    if code == 400
    {
        errorString += " bad request."
    }
}
appendErrorCode(400, toErrorString: &error)
error


//4.返回值
func appendErrorCode1(_ code:Int,toErrorString errorString:inout String) ->String
{
    if code == 400
    {
        errorString += " bad request."
    }
    return errorString;
}
print(appendErrorCode1(400, toErrorString: &error))

//多返回值
func sortedEvenOddNumbers(_ numbers:[Int])->(evens:[Int],odds:[Int])
{
    var evens = [Int]()
    var odds = [Int]()
    for number in numbers
    {
        if number % 2 == 0
        {
            evens.append(number)
        }
        else
        {
            odds.append(number)
        }
    }
    return(evens,odds)
}
let aBunchOfNumbers = [10,1,2,10,34,12,232,423,34,123]
let theSortedNumbers = sortedEvenOddNumbers(aBunchOfNumbers)
print("\(theSortedNumbers.evens)")
print("\(theSortedNumbers.odds)");

//可空类型返回值
func grabMiddleName(fromFullName name:(String,String?,String)) ->String?
{
    return name.1;
}

let middleName = grabMiddleName(fromFullName: ("Matt", nil, "mathias"))
let middleName1 = grabMiddleName(fromFullName: ("Matt", "2ew", "mathias"))


//提前退出函数
/*
 guard语句会根据某个表达式返回的布尔值结果来执行代码；但不同之处是，如果某些条件没有满足可以用guard语句莱提前退出函数。
 */
func greetByMiddleName1(fromFullName name:(first:String,middle:String?,last:String))
{
    guard let middleName:String = name.middle else {
        print("Hey there!")
        return
    }
    print("Hey \(middleName)")
}

greetByMiddleName1(fromFullName: (first: "11", middle: nil, last: "33"))
greetByMiddleName1(fromFullName: (first: "11", middle: "22", last: "33"))


//函数类型
/*
 事实上，所有的函数都有函数类型，函数类型由函数的参数和返回值组成。
 e.g:函数
 func sortedEvenOddNumbers(_ numbers:[Int])->(evens:[Int],odds:[Int])
 的类型是：([Int])->([Int],[Int])
 读作：一个接受整数数组作为参数，并返回带有两个整数数组的元组的函数。
 
 
 e.g:
 let evenOddFunction:([Int])->([Int],[Int]) = sortedEvenOddNumbers  //函数赋值给另外一个该类型的函数
 */


//void
/*
 没有显示返回值的函数还是有返回值的，返回的是void。编译器会帮你在代码中插入这个返回值
 command点击发现，void 是 ()的别名，so，下面几个函数是等价的
 */

func test(){}
func test1()->Void{}
func test2()->(){}
